package edu.vt.ece.rt.dstm;

import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

import edu.vt.ece.rt.quorum.util.Names;
import edu.vt.ece.rt.util.Logger.Logger;

/*
 * To Support different Context types in future
 * @author Sudhanshu
 * TODO: Remove the context after commit or abort
 */
public class ContextDelegator {
	/*
	 * Allow application to access the different Context Locally
	 */
	public static ConcurrentHashMap<Long, Context>	contextMap = new ConcurrentHashMap<Long, Context>();
	
//	/*
//	 * Might not need it, lets see 
//	 */
//	public static ConcurrentHashMap<Long, Context>	parentMap = new ConcurrentHashMap<Long, Context>();
	
	/* Refers to the current execution context */
	public static Context currentContext = null;
	
	
	static Random generator = new Random();
	
//	final private static ContextThreadLocal THREAD_CONTEXT = new ContextThreadLocal();
//
//	private static class ContextThreadLocal extends ThreadLocal<Context>
//	{
//		private Class<?> contextClass;  
//
//		public ContextThreadLocal(){
//			try {
//				this.contextClass = Class.forName(Names.ContextClass);
//				return;
//			} catch (ClassNotFoundException e) {
//				e.printStackTrace(); // TODO add logger
//			}
//		}
//
//		@Override
//		protected synchronized Context initialValue() {
//			try {
//				return (Context)this.contextClass.newInstance();
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//			return null;
//		}
//	}

	public static Context getContext(){
	    return new Context();
	}

	
	public static Context getCurrentContext(){
	    return currentContext;
	}

	public static void setCurrentContext(Context c){
		if (c != null)Logger.debug("Updating the context to "+c.getContextId());
	    currentContext = c;
	}

	/* 
	 * Every time a transaction commits, set
	 * current context as parent  
	 */
	public static void setContextParent() {
		Context child = getCurrentContext();
		if (child != null) {
			Logger.debug("my current Id is "+ child.getContextId());
		} else {
			Logger.debug("WTF");
		}
		if (child.parent != null) {Logger.debug("Back to parent "+ child.getParentContextId());}
		else {
			Logger.debug("For root transaction");
		}
		setCurrentContext(child.parent);
	}
	
	public static Context getNestedContext(){
		
		
	    Context retContext = new Context();
	    retContext.init(1);
	    Logger.debug("Current = "+ retContext.getContextId());
	    return retContext;
	}

	
	synchronized public static Context getContext(Long txnId){
		Context c;
		
		
		if((c=contextMap.get(txnId)) != null) {		//Check if local
//			Logger.debug(" Read txn "+c.getContextId()+" status "+c.getStatus());
			Logger.debug("Got the context!!!!");
			
			return c;
		}
		
		//Create new Context if required, 
		// usually on the remote node
		Logger.debug("Creating new context huh");
		c = new Context(txnId);
		c.register();
		return c;
	}
	
	synchronized public static void removeContext(Context c){
		contextMap.remove(c);
	}
	
//	public static void setParent(Long id, Long parentId) {
//		
//		if (parentId == null) return;
//		
//		parentMap.put(id, getContext(parentId));
//		
//	}
	
}
